package org.demo;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;

import javax.net.ssl.SSLContext;

import org.apache.commons.httpclient.util.HttpURLConnection;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLInitializationException;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sun.net.www.protocol.https.HttpsURLConnectionImpl;

public class HttpRequestUtil {
	private static final Logger LOGGER = LoggerFactory.getLogger(HttpRequestUtil.class);
	private static PoolingHttpClientConnectionManager connectionManager = null;
    private static HttpClientBuilder httpBulder = null;
    private static RequestConfig requestConfig = null;
    private static int MAXCONNECTION = 10;
    private static int DEFAULTMAXCONNECTION = 5;
    private static Charset DEFAULT_CHARSET_OBJ=Charset.defaultCharset();
    private static String DEFAULT_CHARSET=Charset.defaultCharset().name();
    static {
        //设置http的状态参数
        requestConfig = RequestConfig.custom()
                .setSocketTimeout(300000)
                .setConnectTimeout(300000)
                .setConnectionRequestTimeout(300000)
                .build();
        connectionManager = new PoolingHttpClientConnectionManager(getRegistry());
        connectionManager.setMaxTotal(MAXCONNECTION);
        connectionManager.setDefaultMaxPerRoute(DEFAULTMAXCONNECTION);
        // 不设置registry时, 设置这个能访问https 
//        HttpHost target = new HttpHost("cnivi.com.cn", 80);
//        connectionManager.setMaxPerRoute(new HttpRoute(target), 20);
        httpBulder = HttpClients.custom();
        httpBulder.setConnectionManager(connectionManager);
    }
    private static Registry<ConnectionSocketFactory> getRegistry(){
		LayeredConnectionSocketFactory ssl = null;
		try {
			ssl = SSLConnectionSocketFactory.getSystemSocketFactory();
		} catch (final SSLInitializationException ex) {
			final SSLContext sslcontext;
			try {
				//sslcontext = SSLContext.getDefault();
				sslcontext = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
				sslcontext.init(null, null, null);
				ssl = new SSLConnectionSocketFactory(sslcontext);
			} catch (final SecurityException ignore) {
			} catch (final KeyManagementException ignore) {
			} catch (final NoSuchAlgorithmException ignore) {
			}
		}
    	return RegistryBuilder.<ConnectionSocketFactory>create()
    			 .register("http", PlainConnectionSocketFactory.getSocketFactory())
    			.register("https", ssl != null ? ssl : SSLConnectionSocketFactory.getSocketFactory()).build();
    }
    
	public static HttpResponseVO doRequest(HttpRequestVO req) {
		HttpRequestBase request=null;
		HttpResponse response=null;
		HttpResponseVO resp=new HttpResponseVO();
		CloseableHttpClient client=null;
		resp.setTime(System.currentTimeMillis());
		// request.setParams(params);
		String realUrl=req.getUrl();
		if(HttpRequestVO.METHOD_GET.equalsIgnoreCase(req.getMethod())) {
			request=new HttpGet(realUrl);
		}else if(HttpRequestVO.METHOD_POST.equalsIgnoreCase(req.getMethod())) {
			request=new HttpPost(realUrl);
		}
		request.setConfig(requestConfig);
		// header
		if(req.getHeader()!=null) {
			req.getHeader().forEach(request::setHeader);
		}
		
		// entity
		if(HttpEntityEnclosingRequest.class.isInstance(request)) {
			EntityBuilder eb=EntityBuilder.create();
			eb.setContentEncoding(DEFAULT_CHARSET);
			if(req.getBody()!=null) {
				eb.setText(req.getBody());
				eb.setContentType(ContentType.APPLICATION_JSON);
				
			}else if(req.getFormParam()!=null) {
				List<NameValuePair> qparams = new ArrayList<>();
				qparams.add(new BasicNameValuePair("q", "httpclient"));
				eb.setParameters(qparams);
			}
			HttpEntityEnclosingRequest.class.cast(request).setEntity(eb.build());
		}
		
		
		if(req.getFormParam()!=null) {
			
		}
		
		
		try {
			 client= getConnection();
			response=client.execute(request);
			resp.setTime(System.currentTimeMillis()-resp.getTime());
			if(response!=null) {
				StatusLine sl=response.getStatusLine();
				resp.setCode(sl.getStatusCode());
				resp.setMessage(sl.getReasonPhrase());
				String result = EntityUtils.toString(response.getEntity(),DEFAULT_CHARSET);
				resp.setResult(result);
			}
		} catch (Exception e) {
			e.printStackTrace();
			resp.setTime(System.currentTimeMillis()-resp.getTime());
		}finally {
			if(request!=null) {
				//request.releaseConnection();
			}
		}
		return resp;
	}
	
	public static void doGet(String url,Consumer<HttpResponseVO> consumer) {
		HttpRequestVO req=new HttpRequestVO();
		req.setMethod(HttpRequestVO.METHOD_GET);
		req.setUrl(url);
		 consumer.accept(doRequest(req));
	}
	/**
	 * 
	 * 获取远程文件尺寸
	 */

	private static long getRemoteFileSize(String remoteFileUrl) throws IOException {

	    long fileSize = 0;

	    HttpsURLConnectionImpl httpConnection = (HttpsURLConnectionImpl) new URL(

	    remoteFileUrl).openConnection();

	    httpConnection.setRequestMethod("HEAD");

	    int responseCode = httpConnection.getResponseCode();

	    if (responseCode >= 400) {

	        System.out.println("Web服务器响应错误!");

	        return 0;

	    }

	    String sHeader;

	    for (int i = 1;; i++) {

	        sHeader = httpConnection.getHeaderFieldKey(i);

	        if (sHeader != null && sHeader.equals("Content-Length")) {

	            System.out.println("文件大小ContentLength:"
	                    + httpConnection.getContentLength());

	            fileSize = Long.parseLong(httpConnection
	                    .getHeaderField(sHeader));

	            break;

	        }

	    }

	    return fileSize;

	}
	public static void doDownload(String url,File file) {
		CloseableHttpClient httpClient=null;
		int offset=0;
		long length=0;
		try {
			length=getRemoteFileSize(url);

	        HttpGet httpGet = new HttpGet(url);
	        httpGet.addHeader("Range", "bytes=" + offset + "-"
	                + (offset + length - 1));
	        httpClient=getConnection();
	        CloseableHttpResponse response = httpClient.execute(httpGet);
	        BufferedInputStream bis = new BufferedInputStream(response
	                .getEntity().getContent());

	        byte[] buff = new byte[1024];

	        int bytesRead;


	        RandomAccessFile raf = new RandomAccessFile(file, "rw");

	        while ((bytesRead = bis.read(buff, 0, buff.length)) != -1) {
	            raf.seek(offset);
	            raf.write(buff, 0, bytesRead);
	            offset = offset + bytesRead;
	        }
	        raf.close();
	        bis.close();
	    } catch (ClientProtocolException e) {
	        LOGGER.error("DownloadThread exception msge",e);
	    } catch (IOException e) {
	        LOGGER.error("DownloadThread exception msge",e);
	    } finally {
	        System.out.println(length+ " is go on!");
	    }
	}
	
	
	
	private static CloseableHttpClient getConnection() {
        return httpBulder.build();
    }
	public static void main(String[] args) throws Exception {
		//doGet("http://localhost:9200/", System.out::print);
//		doGet("https://www.baidu.com", System.out::print);
		System.out.println(">>>>>>>"+getRemoteFileSize("https://www.baidu.com"));
//		doGet("https://www.baidu.com", System.out::print);

	}

}
